;; This file is part of scheme-GNUnet.
;; Copyright (C) 2021 GNUnet e.V.
;;
;; scheme-GNUnet is free software: you can redistribute it and/or modify it
;; under the terms of the GNU Affero General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version.
;;
;; scheme-GNUnet is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;
;; SPDX-License-Identifier: AGPL-3.0-or-later

(import (gnu gnunet utils bv-slice)
	(gnu gnunet crypto)
	(gnu gnunet hashcode struct)
	(only (gnu gnunet netstruct syntactic)
	      sizeof)
	(only (gcrypt base16)
	      base16-string->bytevector)
	(only (rnrs bytevectors)
	      make-bytevector string->utf8)
	(srfi srfi-64)
	(only (srfi srfi-43)
	      vector-every)
	(only (ice-9 match)
	      match))

;; Two test vectors from
;; https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/sha/Sha-2-512.unverified.test-vectors
(define test-vectors/sha512
  #(#(""
      "CF83E1357EEFB8BDF1542850D66D8007"
      "D620E4050B5715DC83F4A921D36CE9CE"
      "47D0D13C5D85F2B0FF8318D2877EEC2F"
      "63B931BD47417A81A538327AF927DA3E")
    #("abc"
      "DDAF35A193617ABACC417349AE204131"
      "12E6FA4E89A97EA20A9EEEE64B55D39A"
      "2192992A274FC1A836BA3C23A3FEEBBD"
      "454D4423643CE80E2A9AC94FA54CA49F")))

(define (test-vector bits hash-slice! test-vector)
  (match test-vector
    (#(string hash-part/0 hash-part/1 hash-part/2 hash-part/3)
     (define hash/base16 (string-append hash-part/0 hash-part/1 hash-part/2
					hash-part/3))
     (define hash/expected
       (base16-string->bytevector (string-downcase hash/base16)))
     ;; #xde: bogus filler, should be overwritten
     (define hash/received (make-bytevector (/ bits 8) #xde))
     (hash-slice! (slice/read-only
		   (bv-slice/read-write
		    (string->utf8 (string-append "don't" string "useme")))
		   ;; The string length is also the bytevector
		   ;; length, because the strings are restricted to ASCII.
		   (string-length "don't")
		   (string-length string))
		  (slice/write-only
		   (bv-slice/read-write hash/received)))
     (when (not (equal? hash/expected hash/received))
       (pk 'oops hash/expected hash/received))
     (pk 'ok)
     (equal? hash/expected hash/received))))

(define (test-vectors bits hash-slice! vectors)
  (vector-every (lambda (vector)
		  (test-vector bits hash-slice! vector))
		vectors))

(test-assert "hash/sha512!, test vectors"
  (test-vectors 512 hash/sha512! test-vectors/sha512))

(test-error "hash/sha512!, requires readability"
  (hash/sha512! (slice/write-only (make-slice/read-write 400))
		(make-slice/read-write (/ 512 8))))

(test-error "hash/sha512!, requires writability"
  (hash/sha512! (make-slice/read-write 400)
		(slice/read-only (make-slice/read-write (/ 512 8)))))

(test-equal "size of /hashcode:512"
  512
  (* 8 (sizeof /hashcode:512 '())))
